﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.Windows.Threading;
using GT.Net;
using GT.UI;
using System.Windows.Forms;

namespace BallTest
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        // GT instance variables
        private Client client;
        private IStringChannel messageChannel;
        private IObjectChannel positionChannel;
        private ISessionChannel sessionChannel;
        private const int MessagesChannelId = 1;
        private const int SessionChannelId = 0;
        private const int PositionChannelId = 2;

        // Timer
        DispatcherTimer gameLoopTimer;

        // Dictionary for screen blobs
        Dictionary<int, Ellipse> blobs;

        // The object representing our blob that we will send around
        Blob myBlob;
        Ellipse me;

        public Window1()
        {
            InitializeComponent();

            // Input dialog to get host and port of server

            InputDialog d = new InputDialog("Connection details", "Which server:port ?", "localhost:9999");
            DialogResult result = d.ShowDialog();
            if (!result.ToString().Equals("OK"))
            {
                throw new InvalidOperationException();
            }
            string[] parts = d.Input.Split(':');
            string host = parts[0];
            string port = parts.Length > 1 ? parts[1] : "9999";

            // Create GT client and set up communication channels

            client = new Client();
            client.ConnexionRemoved += client_ConnexionRemoved;
            client.Start();

            messageChannel = client.OpenStringChannel(host, port, MessagesChannelId, ChannelDeliveryRequirements.ChatLike);
            sessionChannel = client.OpenSessionChannel(host, port, SessionChannelId, ChannelDeliveryRequirements.SessionLike);
            positionChannel = client.OpenObjectChannel(host, port, PositionChannelId, ChannelDeliveryRequirements.AwarenessLike);

            // Set up the game loop timer
            gameLoopTimer = new DispatcherTimer();
            gameLoopTimer.Interval = TimeSpan.FromMilliseconds(50);
            gameLoopTimer.Tick += new EventHandler(timer_Tick);
            gameLoopTimer.Start();

            // Blob dictionary
            blobs = new Dictionary<int,Ellipse>();
            myBlob = new Blob();
            myBlob.x = 100;
            myBlob.y = 100;
            myBlob.id = positionChannel.Identity;
            // here would be a good place to put a color picker so that each person has a different color!
            myBlob.color = Color.FromArgb(255, 255, 255, 0);

            me = new Ellipse();
            me.Width = 50;
            me.Height = 50;
            me.Fill = new SolidColorBrush(myBlob.color);
            me.Stroke = Brushes.DarkGray;
            me.StrokeThickness = 2;
            blobs[0] = me;

            canvas1.Children.Add(me);
            Canvas.SetLeft(me, 100);
            Canvas.SetTop(me, 100);
            Canvas.SetZIndex(me, 1);

        }

        // What to do when we lose our connection to the server
        private void client_ConnexionRemoved(Communicator c, IConnexion conn)
        {
            if (this.IsActive && client.Connexions.Count == 0)
            {
                System.Windows.MessageBox.Show(this, "Disconnected from server. Closing application.");
                Close();
            }
        }

        // GT game loop: checks for incoming messages and processes them; also sends my posistion
        private void timer_Tick(object sender, EventArgs e)
        {
            // process incoming messages

            client.Update();

            String str;
            while ((str = messageChannel.DequeueMessage(0)) != null)
                processTextMessage(str);

            Object obj;
            while ((obj = positionChannel.DequeueMessage(0)) != null)
                processObject(obj);

            SessionMessage mes;
            while ((mes = sessionChannel.DequeueMessage(0)) != null)
                processSessionMessage(mes);

            // send my position

            if (positionChannel.Active)
            {
                positionChannel.Send(myBlob);
                messageChannel.Send("test");
            }

            // hack; update screen blob
            Canvas.SetLeft(me, myBlob.x);
            Canvas.SetTop(me, myBlob.y);

        }

        private void processTextMessage(string message)
        {
            Console.WriteLine("timer tick");

            Console.WriteLine(message);
        }

        private void processObject(object obj)
        {
            Blob posn = (Blob)obj;
            if (blobs.ContainsKey(posn.id))
            {
                Ellipse ell = blobs[posn.id];
                Canvas.SetLeft(ell, posn.x);
                Canvas.SetTop(ell, posn.y);
            }
            else
            {
                Ellipse newPerson = new Ellipse();
                newPerson.Width = 50;
                newPerson.Height = 50;
                newPerson.Fill = new SolidColorBrush(posn.color);
                newPerson.Stroke = Brushes.DarkGray;
                newPerson.StrokeThickness = 2;
                blobs[posn.id] = newPerson;

                canvas1.Children.Add(newPerson);
                Canvas.SetLeft(newPerson, 100);
                Canvas.SetTop(newPerson, 100);
                Canvas.SetZIndex(newPerson, 1);
            }
        }

        private void processSessionMessage(SessionMessage sessMess)
        {

        }

        private void Quit(object sender, RoutedEventArgs e)
        {
            client.Stop();
            client.Dispose();
        }

        private void OnMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            myBlob.x = e.GetPosition(canvas1).X;
            myBlob.y = e.GetPosition(canvas1).Y;
        }
    }

    [Serializable]
    public class Blob
    {
        public double x;
        public double y;
        public int id;
        public Color color;
    }
}
